﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using KylinORM.Aspect;
using System.Reflection;
using KylinORM.Utils;
using KylinORM.CQRS.Publisher;
using KylinORM.CQRS.Subscriber;
using KylinORM.CQRS.Subscriber.Generic;

namespace KylinORM.CQRS
{
    /// <summary>
    /// 消息总线
    /// </summary>
    public sealed class MessageBus : IEndpoint
    {
        #region 静态方法
        /// <summary>
        /// 命令端点
        /// </summary>
        public static IEndpoint CommandService = MessageBus.NewEndpoint(CommandServiceUrl);
        /// <summary>
        /// 命令端点地址
        /// </summary>
        public const string CommandServiceUrl = "object://KylinORM.CQRS/MessageBus/CommandService";
        /// <summary>
        /// 事件端点
        /// </summary>
        public static IEndpoint EventService = MessageBus.NewEndpoint(EventServiceUrl);
        /// <summary>
        /// 事件端点地址
        /// </summary>
        public const string EventServiceUrl = "object://KylinORM.CQRS/MessageBus/EventService";

        /// <summary>
        /// 创建一个新的消息端点
        /// </summary>
        /// <returns></returns>
        public static IEndpoint NewEndpoint()
        {
            return new MessageBus(new Uri("object://KylinORM.CQRS/MessageBus/" + Guid.NewGuid()));
        }
        /// <summary>
        /// 创建一个新的消息端点
        /// </summary>
        /// <param name="enpointUrl">消息端点地址，格式object://命名空间/类名/属性名</param>
        /// <returns></returns>
        public static IEndpoint NewEndpoint(string enpointUrl)
        {
            return new MessageBus(new Uri(enpointUrl));
        }
        /// <summary>
        /// 为当前程序集注册默认消息端点的响应
        /// </summary>
        public static void RegisterHandler()
        {
            RegisterHandler(Assembly.GetCallingAssembly(), CommandService);
            RegisterHandler(Assembly.GetCallingAssembly(), EventService);
        }
        /// <summary>
        /// 为指定程序集注册指定消息端点的响应
        /// </summary>
        /// <param name="assembly"></param>
        /// <param name="endpoint"></param>
        public static void RegisterHandler(Assembly assembly, IEndpoint endpoint)
        {
            foreach (Type type in assembly.GetTypes())
            {
                //不查找使用<% %>嵌入页面中代码
                if (type.Namespace == "ASP")
                    continue;
                RegisterHandler(type, endpoint);
            }
        }
        /// <summary>
        /// 为指定类注册指定消息端点的响应
        /// </summary>
        /// <param name="type"></param>
        /// <param name="endpoint"></param>
        public static void RegisterHandler(Type type, IEndpoint endpoint)
        {
            foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static))
            {
                object[] handlers = method.GetCustomAttributes(typeof(OnMessageAttribute), false);
                foreach (OnMessageAttribute handler in handlers)
                {
                    if (!handler.EndpointUrl.Equals(endpoint.Url))
                        continue;

                    if (handler.MessageType.HasValue)
                        endpoint.On(handler.MessageName, TypeConverter.CreateDelegate(method), handler.MessageType.Value);
                    else
                        endpoint.On(handler.MessageName, TypeConverter.CreateDelegate(method));
                }
            }
        }
        #endregion

        private MessageBus(Uri endpointUrl)
        {
            this.Url = endpointUrl;
        }

        #region IEndpoint 成员
        /// <summary>
        /// 当前已注册的消息响应
        /// </summary>
        private Dictionary<string, List<MessageHandler>> messageHandlers = new Dictionary<string, List<MessageHandler>>();

        /// <summary>
        /// 注册消息响应
        /// </summary>
        /// <param name="messageName">消息名称</param>
        /// <param name="callbackFunc">消息响应的回调方法</param>
        public void On(string messageName, Delegate callbackFunc)
        {
            this.On(messageName, new MessageHandler(callbackFunc));
        }
        /// <summary>
        /// 注册消息响应
        /// </summary>
        /// <param name="messageName">消息名称</param>
        /// <param name="callbackFunc">消息响应的回调方法</param>
        /// <param name="messageType">消息响应的类型</param>
        public void On(string messageName, Delegate callbackFunc, EMessageType messageType)
        {
            this.On(messageName, new MessageHandler(new MessageHandlerItem(callbackFunc, messageType)));
        }
        /// <summary>
        /// 注册消息响应
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="messageName">消息名称</param>
        /// <param name="callbackFunc">消息响应的回调方法</param>
        public void On<T>(string messageName, Action<T> callbackFunc) where T : IMessage
        {
            this.On(messageName, new MessageHandler<T>(callbackFunc));
        }
        /// <summary>
        /// 注册消息响应
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="messageName">消息名称</param>
        /// <param name="callbackFunc">消息响应的回调方法</param>
        /// <param name="messageType">消息响应的类型</param>
        public void On<T>(string messageName, Action<T> callbackFunc, EMessageType messageType) where T : IMessage
        {
            this.On(messageName, new MessageHandler<T>(new MessageHandlerItem<T>(callbackFunc, messageType)));
        }
        /// <summary>
        /// 注册消息响应
        /// </summary>
        /// <param name="messageName">消息名称</param>
        /// <param name="messageHandler">消息响应</param>
        public void On(string messageName, MessageHandler messageHandler)
        {
            lock (messageHandlers)
            {
                if (!messageHandlers.ContainsKey(messageName))
                    messageHandlers.Add(messageName, new List<MessageHandler>());

                messageHandlers[messageName].Add(messageHandler);
            }
        }
        /// <summary>
        /// 得到已注册的消息响应
        /// </summary>
        /// <param name="messageName"></param>
        /// <returns></returns>
        public List<MessageHandler> GetHandlers(string messageName)
        {
            return messageHandlers[messageName] ?? new List<MessageHandler>();
        }
        /// <summary>
        /// 是否已注指定的消息
        /// </summary>
        /// <param name="messageName"></param>
        /// <returns></returns>
        public bool HasHandler(string messageName)
        {
            return messageHandlers.ContainsKey(messageName);
        }
        /// <summary>
        /// 将消息发送到已注册的响应程序
        /// </summary>
        /// <param name="message">消息对象</param>
        public void Send(IMessage message)
        {
            if (messageHandlers.Keys.Contains(message.MessageName))
            {
                messageHandlers[message.MessageName].ForEach(messageHandler =>
                {
                    messageHandler.Apply(message);
                });
            }
        }

        /// <summary>
        /// 消息端点地址，格式object://命名空间/类名/属性名
        /// </summary>
        public Uri Url { get; set; }
        #endregion


    }
}
